/* ----------------------------------------------------------------------------

	pax.widget.optiontransfer.js Copyright (C) 2002, 2005, 2009 Mikkel Bergmann, Pointful

	Licence
	-------
	
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

	See lgpl.txt for licence details

---------------------------------------------------------------------------- */
/*
	Script: pax.widget.optiontransfer
		This widget allow you to transfer options from one select to another
		
	Author:
		Mikkel Bergmann, <http://www.pointful.com>
*/

var pax = pax || {};
pax.widget = pax.widget || {};
pax.widget.optiontransfer = pax.widget.optiontransfer || {};

/*	Method: pax.widget.optiontransfer.init
	Initialises the optiontransfer widget.
	
	Parameters:
		target - the output DOM element
		args - optional argument object, ie: {}
		* options1 - list with options for the first select
		* options2 - list with options for the second select
		* size - how many options each select displays default = 7
		* sort - shall we sort the options as they are moved around, default = false
		* fieldName1 - name for field 1, default = 'fieldName1[]'
		* fieldName2 - name for field 2, default = 'fieldName2[]'
		* fieldId1 - ID for field 1, default = 'fieldId1'
		* fieldId2 - ID for field 2, default = 'fieldId2'
		* header1 - field 1 header, default = 'Available'
		* header2 - field 2 header, default = 'Selected'
		* move1Label - label for the move1 button, default = '&raquo;'
		* move2Label - label for the move2 button, default = '&laquo;'
		* moveAll1Label - label for the moveAll1 button, default = '&raquo;&raquo;'
		* moveAll2Label - label for the moveAll2 button, default = '&laquo;&laquo;'
		* showMove1 - shall we show the move1 button, default = true
		* showMove2 - shall we show the move2 button, default = true
		* showMoveAll1 - shall we show the moveAll1 button, default = true
		* showMoveAll2 - shall we show the moveAll2 button, default = true
		* optionFilter - function that returns options we allow to move

	Returns:
		nothing

	Example:
		(start code)
			<div id='pax.widget.optiontransfer.example'>
				<select id='field1' name='field1[]'>
					<option value='1'>honey cake</option>
					<option value='2'>jam donut</option>
					<option value='3'>chocolate chip muffin</option>
				</select>
				
				<select id='field2' name='field2[]'>
					<option value='5'>Vanilla slice</option>
					<option value='4'>Rasphberry tartlet</option>
					<option value='6'>Lemon merang</option>
					<option value='9'>Banana split</option>
				</select>
			</div>
			[:
				pax.load.onloaded( function() {
					//	Optiontransfer example generated from existing HTML
					pax.widget.optiontransfer.init( pax.$('pax.widget.optiontransfer.example'), {
						options1: pax.$('field1'),
						options2: pax.$('field2')
					} );
					
				} );
			:]
			This will create a default optiontransfer widget 
		(end)
*/
pax.widget.optiontransfer.init = function( target, args ) {
	args.target = target;	//	Set the target for the arguments
	
	var model = pax.widget.optiontransfer.model( target, args );
	
	var options1Type = pax.util.getType( model.options1 );
	var options2Type = pax.util.getType( model.options2 );
	
	//	options can be select boxes
	if( options1Type == 'element' )model.options1 = pax.form.getOptionsAsObjectList( model.options1 );
	if( options2Type == 'element' )model.options2 = pax.form.getOptionsAsObjectList( model.options2 );
	
	function objToOptionList( obj ) {
		var list = [];
		for( var i in obj )list.push( { value: i, text: obj[i] } );
		return list;
	}
	
	//	options can be specified as objects instead of lists
	if( options1Type == 'object' )model.options1 = objToOptionList( model.options1 );
	if( options2Type == 'object' )model.options2 = objToOptionList( model.options2 );
	
	var bindElements = {
		internal: {
			'moveToOption2': {
				'click': function(e) {
					pax.widget.optiontransfer.moveSelectedOptions( model, pax.$( model.fieldId1 ), pax.$( model.fieldId2 ) );
				}
			},
			'moveToOption1': {
				'click': function(e) {
					pax.widget.optiontransfer.moveSelectedOptions( model, pax.$( model.fieldId2 ), pax.$( model.fieldId1 ) );
				}
			},
			'moveAllToOption2': {
				'click': function(e) {
					pax.widget.optiontransfer.moveAllOptions( model, pax.$( model.fieldId1 ), pax.$( model.fieldId2 ) );
				}
			},
			'moveAllToOption1': {
				'click': function(e) {
					pax.widget.optiontransfer.moveAllOptions( model, pax.$( model.fieldId2 ), pax.$( model.fieldId1 ) );
				}
			}
		},
		id: {}
	};
	
	//	Bind double clicking
	bindElements['id'][model.fieldId1] =  {
		'dblclick': function( e ) {
			pax.widget.optiontransfer.moveSelectedOptions( model, pax.$( model.fieldId1 ), pax.$( model.fieldId2 ) );
		}
	};

	bindElements['id'][model.fieldId2] =  {
		'dblclick': function( e ) {
			pax.widget.optiontransfer.moveSelectedOptions( model, pax.$( model.fieldId2 ), pax.$( model.fieldId1 ) );
		}
	};
	
	pax.widget.init( {
		target: target,
		model: model,
		template: pax.widget.optiontransfer.template(),
		bindElements: bindElements
	} ).render();

	
	//	Sort on init; use the generic moveAllOptions function
	if( model.sort ) {
		pax.widget.optiontransfer.moveAllOptions( model, pax.$( model.fieldId1 ), pax.$( model.fieldId1 ) );
		pax.widget.optiontransfer.moveAllOptions( model, pax.$( model.fieldId2 ), pax.$( model.fieldId2 ) );
	}
	
	//	Bind the form to select both boxes on submit
	//	TODO: Manual method for this on ajax submit.
	pax.event.bind( pax.$( model.fieldId1 ).form, 'submit', function() {
		pax.widget.optiontransfer.selectOptions( model );
	} );
	
};

//	Selects both boxes
pax.widget.optiontransfer.selectOptions = function( model ) {
	var box1 = pax.$( model.fieldId1 );
	var box2 = pax.$( model.fieldId2 );
	pax.form.setSelected( box1 );
	pax.form.setSelected( box2 );
};

//	Transfers selected options to the given select box
//	Note: we only sort the toSelect, as we assume the options are already sorted
//pax.widget.optiontransfer.moveSelectedOptions = function( fromSelect, toSelect, sort ) {
pax.widget.optiontransfer.moveSelectedOptions = function( model, fromSelect, toSelect ) {
	//fromSelect = fromSelect || pax.$( model.fieldId1 );
	//toSelect = toSelect || pax.$( model.fieldId2 );
	var options = pax.form.getSelectedOptions(fromSelect) || [];
	var toOptions = model.optionFilter( options, fromSelect, toSelect );
	pax.form.addOption( toOptions, toSelect );
	pax.form.removeOption( toOptions, fromSelect );
	if( model.sort )pax.widget.optiontransfer.sortSelect( toSelect, model.sort );
	fromSelect.selectedIndex = -1;
	toSelect.selectedIndex = -1;
};

//	Transfers all options to the given select box
//	pax.widget.optiontransfer.moveAllOptions = function( fromSelect, toSelect, sort ) {
pax.widget.optiontransfer.moveAllOptions = function( model, fromSelect, toSelect ) {
	pax.form.setSelected( fromSelect );
	pax.widget.optiontransfer.moveSelectedOptions( model, fromSelect, toSelect );
};

//	Default option sort function.
pax.widget.optiontransfer.defaultSortFunc = function( a, b ) {
	var aText = (a.text)? a.text.toLowerCase(): '';
	var bText = (b.text)? b.text.toLowerCase(): '';
	if( ( aText + '' ) < ( bText + '' ) )return -1;
	if( ( aText + '' ) > ( bText + '' ) )return 1;
	return 0;
};

//	Sorts options by given sort func.
pax.widget.optiontransfer.sortSelect = function( target, sortFunc ) {
	var options = pax.form.getOptions( target ) || [];
	//	Use either custome or default sort function
	sortFunc = (typeof sortFunc == 'function')? sortFunc: pax.widget.optiontransfer.defaultSortFunc;
	
	options = options.sort( sortFunc );
	
	pax.form.removeOption( options, target );
	pax.form.addOption( options, target );
};

//  "Model" method
pax.widget.optiontransfer.model = function( target, args ) {
	args.target = target;
	
	var model = pax.defaultArgs( {
		target: null,
		size: 7,
		sort: false,
		options1: [],
		options2: [],
		fieldName1: 'fieldName1[]',
		fieldName2: 'fieldName2[]',
		fieldId1: 'fieldId1',
		fieldId2: 'fieldId2',
		header1: 'Available',
		header2: 'Selected',
		move1Label: '&raquo;',
		move2Label: '&laquo;',
		moveAll1Label: '&raquo;&raquo;',
		moveAll2Label: '&laquo;&laquo;',
		showMove1: true,
		showMove2: true,
		showMoveAll1: true,
		showMoveAll2: true,
		optionFilter: function( options ) { return options; }	//	returns options allowed to move
	}, args );
	
	//	Auto-generate the field names and IDs if necessary.
	if( model['fieldId1'] == 'fieldId1' )model['fieldId1'] = model['fieldId1'] + pax.getNextId();
	if( model['fieldId2'] == 'fieldId2' )model['fieldId2'] = model['fieldId2'] + pax.getNextId();
	
	return model;
};

/*	Method: pax.widget.optiontransfer.template
	Returns a PAX template for the widget
*/
pax.widget.optiontransfer.template = function() {
	var template = "" +
		"<div class='paxOptiontransferContainer'>" +
		"	<p class='paxOptiontransferField'>" +
		"		<label for='[:= fieldName1 :]'>" +
		"			[:= header1 :]" +
		"		</label>" +
		"		<br/>" +
		"		<select name='[:= fieldName1 :]' multiple size='[:= size :]' class='span-4' id='[:= fieldId1 :]'/>" +
		"			[: for( var i in options1 ) { if( options1.hasOwnProperty(i) ) { :]" +
		"			<option value='[:= options1[i].value :]'>[:= options1[i].text :]</option>" +
		"			[: } } :]" +
		"		</select>" +
		"	</p>" +
		"	<p class='paxOptiontransferButtonSurround'>" +
		"		[: if( showMoveAll1 ) { :]<button class='paxOptiontransferButton' id='[:= pax.widget.getInternalID( 'moveAllToOption2', target ) :]' type='button'>[:= moveAll1Label :]</button>[: } :]" +
		"		[: if( showMove1 ) { 	:]<button class='paxOptiontransferButton' id='[:= pax.widget.getInternalID( 'moveToOption2', target ) :]' type='button'>[:= move1Label :]</button>[: } :]" +
		"		[: if( showMove2 ) { 	:]<button class='paxOptiontransferButton' id='[:= pax.widget.getInternalID( 'moveToOption1', target ) :]' type='button'>[:= move2Label :]</button>[: } :]" +
		"		[: if( showMoveAll2 ) { :]<button class='paxOptiontransferButton' id='[:= pax.widget.getInternalID( 'moveAllToOption1', target ) :]' type='button'>[:= moveAll2Label :]</button>[: } :]" +
		"	</p>" +
		"	<p class='paxOptiontransferField'>" +
		"		<label for='[:= fieldName2 :]'>" +
		"			[:= header2 :]" +
		"		</label>" +
		"		<br/>" +
		"		<select name='[:= fieldName2 :]' multiple size='[:= size :]' class='span-4' id='[:= fieldId2 :]'/>" +
		"			[: for( var i in options2 ) { if( options2.hasOwnProperty(i) ) {:]" +
		"			<option value='[:= options2[i].value :]'>[:= options2[i].text :]</option>" +
		"			[: } } :]" +
		"		</select>" +
		"	</p>" +
		"</div>" +
	"";

	return template;
};
